package com.meatball.authorization.config

import com.meatball.authorization.repository.UserRepository
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.authentication.AuthenticationManager
import org.springframework.security.authentication.AuthenticationProvider
import org.springframework.security.authentication.dao.DaoAuthenticationProvider
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.crypto.password.PasswordEncoder

@Configuration
class ApplicationConfig(private val userRepository: UserRepository) {
    /**
     * TODO 获取用户详情Bean
     * 根据username查询是否存在用户,如果不存在throw用户未找到异常
     */
    @Bean
    fun userDetailsService(): UserDetailsService {
        return UserDetailsService { username ->
            userRepository.findByUsername(username) ?: throw IllegalArgumentException("用户不存在。")
        }
    }

    /**
     * TODO 身份验证Bean
     * 传入获取用户信息的bean & 密码加密器
     * 可以回看一下SecurityConfiguration中 AuthenticationProvider的配置,使用的就是这里注入到容器中的Bean
     * 这个bean 主要是用于用户登录时的身份验证,当我们登录的时候security会帮我们调用这个bean的authenticate方法
     */
    @Bean
    fun authenticationProvider(): AuthenticationProvider {
        val authProvider = DaoAuthenticationProvider()
        // 设置获取用户信息的bean
        authProvider.setUserDetailsService(userDetailsService())
        // 设置密码加密器
        authProvider.setPasswordEncoder(passwordEncoder())
        return authProvider
    }

    /**
     * TODO 身份验证管理器
     *
     * @param config
     */
    @Bean
    fun authenticationManager(config: AuthenticationConfiguration): AuthenticationManager {
        return config.authenticationManager
    }

    /**
     * TODO 码加密器
     * 主要是用来指定数据库中存储密码的加密方式,保证密码非明文存储
     * 当security需要进行密码校验时,会把请求传进来的密码进行加密,然后和数据库中的密码进行比对
     */
    @Bean
    fun passwordEncoder(): PasswordEncoder {
        return BCryptPasswordEncoder()
    }
}